#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <linux/types.h>
#include <setjmp.h>
#include <linux/fb.h>
#include <string.h>
static   int      fd;
typedef unsigned short WORD;
typedef unsigned int DWORD;
typedef struct tagBITMAPFILEHEADER{
  WORD bfType;      //值为0x4d42
  DWORD bfSize;      //位图文件的大小
  DWORD bfReserved;
  DWORD bfOffBits;

}__attribute__ ((packed)) BITMAPFILEHEADER;


typedef struct tagBITMAPINFOHEADER{
DWORD biSize;     //位图信息头的字节数sizeof(BITMAPINFOHEADER)
DWORD biWidth;     //以像素为单位的图像宽度
DWORD biHeight;     //以像素为单位的图像长度
WORD biPlanes;    //目标设备的位平面数
WORD biBitCount;    //每个像素的位数【1】
DWORD biCompression;   //图像的压缩格式（这个值几乎总是为0）
DWORD biSizeImage;   //以字节为单位的图像数据的大小
DWORD biXPelsPerMeter;   //水平方向上的每米的像素个数
DWORD biYPelsPerMeter;   //垂直方向上的每米的像素个数
DWORD biClrUsed;    //调色板中实际使用的颜色数，通常为0
DWORD biClrImportant;   //实现位图时必须的颜色数，通常为0
}__attribute__ ((packed)) BITMAPINFOHEADER;



int draw_bmp(unsigned char *fb_p,unsigned char *bmp_data,int screen_x,int screen_y,int ori_x,int ori_y,int screen_bpp,int bmp_height,int linesize)
{
int i;
unsigned char *tmp_fb_p;
    tmp_fb_p=fb_p;
fb_p=fb_p+ori_x*screen_bpp+screen_x*(screen_y-ori_y)*screen_bpp;
for(i=0;i<bmp_height;i++)
{
if((int)(fb_p-tmp_fb_p)>(screen_y*screen_x*screen_bpp))
{
return -1;
}
memcpy(fb_p,bmp_data,linesize);
fb_p=fb_p+screen_x*screen_bpp;
bmp_data=bmp_data+linesize;


}
return 0;
}

int main(int argc,char *argv[])
{
      int fp1;
      int fbfd=0;
	int ret=0;
    struct fb_var_screeninfo vinfo; 
    struct fb_fix_screeninfo finfo; 
    int start_x = 0 , start_y = 0; 
    long int location = 0 ; 
    static unsigned char *fbp = 0;
    unsigned char *bmp_data;
	long int screensize = 0; 
	BITMAPFILEHEADER   bf;
      BITMAPINFOHEADER   bi;
if((argv[1]=="-"&&argv[2]=="h")||(argv[1]==NULL)||(argv[2]==NULL)||(argv[3]==NULL)||(argv[4]==NULL))
{
printf("example: bmp2fb /dev/fb0 ./1.bmp x  y\n");
return 1;
 }
start_x=atoi(argv[3]);
start_y=atoi(argv[4]);


     fbfd=open(argv[1],O_RDWR); 
	if(!fbfd){ 
            printf("Error:cannot open the framebuffer device!\n"); 
            exit(1); 
        } 

    printf("well you open the framebuffer sucessful!\n"); 
//get the fixed screen information 
    if(ioctl(fbfd,FBIOGET_FSCREENINFO,&finfo))
	{ 
            printf("Error reading fixed information\n"); 
            exit(2); 
        } 
//get the variable screen information 
    if(ioctl(fbfd,FBIOGET_VSCREENINFO,&vinfo))
	{ 
            printf("Error reading variable information\n"); 
            exit(3); 
        }  
//show these information 
    printf("vinfo.xres=%d\n",vinfo.xres); 
    printf("vinfo.yres=%d\n",vinfo.yres); 
    printf("vinfo.bit_per_bits=%d\n",vinfo.bits_per_pixel); 
	 screensize = vinfo.xres * vinfo.yres * vinfo.bits_per_pixel / 8; 
	 fbp = (unsigned char *)mmap(0, screensize, PROT_READ | PROT_WRITE, MAP_SHARED, fbfd, 0); 
       fp1=open(argv[2],O_RDWR); 
      if(!fp1)
      {
          printf("open %s error\n",argv[2]);
          exit(4);
      }
      read(fp1,&bf,14);
      read(fp1,&bi, 40);
	bmp_data=(unsigned char *)malloc( bi.biSizeImage); 
	 read(fp1,bmp_data,bi.biSizeImage); 
	if((bi.biWidth>vinfo.xres)||(bi.biHeight>vinfo.yres)||(bi.biBitCount>vinfo.bits_per_pixel)||(bf.bfType!=0x4d42))
	{
		printf("the photo type is not bmp or width/height is to big\n");
		exit(5);
	} 
  printf("bi.biHeight=%d\n",bi.biHeight); 
    printf("linesize=%d\n",bi.biWidth*bi.biBitCount/8); 
if(start_x>vinfo.xres)
	start_x=vinfo.xres;
if(start_y>vinfo.yres)
	start_y=vinfo.yres;

	ret=draw_bmp(fbp,bmp_data,vinfo.xres,vinfo.yres,start_x,start_y,vinfo.bits_per_pixel/8,bi.biHeight,bi.biWidth*bi.biBitCount/8);
	if(ret==-1)
	{
		printf("some picture data display is lost\n");
	}

      close(fp1);
	 munmap(fbp, screensize); 
	close(fbfd);
	free(bmp_data);

      return 1;
}

